# 回测中使用的模拟交易员
# put_order不是向queue中推行情，而是直接
# 对于market order，直接以对手价成交
# 对于limit order，每个tick检查是否符合成交条件。
#     此处仅看价格是否满足成交条件，不管量是否满足。
from ITrader import ITrader
from common.OrderUpdate import OrderUpdate


class MockTrader(ITrader):

    def __init__(self):
        super().__init__()

    # 覆盖put_event，直接调用对应函数
    # 这里只考虑order和order_update，其他情况没有应用
    def put_event(self, evt_type, data):
        if evt_type == 'order':
            self.execute_order(data)
        elif evt_type == 'order_update':
            self.process_order_update(data)

    # 检查是否有订单可以模拟成交，为了避免浪费cpu资源，也仅检查最近更新的股票
    # init_check是在下单时就检查，对于限价单，下单时可以以更优的盘口成交，但后续只能按订单价格成交
    # 对于
    def check_order(self, inst_id, init_check=False):
        # keys = list(self.system_order_list.keys())
        for key in self.system_order_list.keys():
            # 找到对应品种的剩余订单
            order = self.system_order_list[key]
            if order.volume == 0:
                continue
            if order.inst_id == inst_id:
                (bid, bid_v, ask, ask_v) = self.public_context.get_order_book(inst_id)
                # 对于市价订单
                if order.order_type == 'market_order':
                    if (order.direction == 'BUY' and ask_v) or (order.direction == 'SELL' and bid_v):
                        # 确定成交价格和数量
                        deal_price = ask if order.direction == 'BUY' else bid
                        deal_volume = order.volume
                    else:
                        continue
                # 对于限价订单
                else:
                    if (order.direction == 'BUY' and order.price >= ask and ask_v) or \
                            (order.direction == 'SELL' and order.price <= bid and bid_v):
                        # 确定成交价格
                        if init_check:
                            deal_price = ask if order.direction == 'BUY' else bid
                        else:
                            deal_price = order.price
                        deal_volume = order.volume
                    else:
                        continue
                # 确定成交金额和手续费
                amount = deal_price * deal_volume
                fee = max(5.0, amount * 0.0003)
                if order.direction == 'SELL':
                    fee += amount * 0.001
                fee = round(fee, 2)
                amount = amount + fee if order.direction == 'BUY' else amount - fee
                # 生成成交回报
                order_update = OrderUpdate(order.strategy_name, order.strategy_order_id, order.system_order_id, 'DEAL',
                                           inst_id, order.direction, order.volume, deal_price, amount, fee)
                self.process_order_update(order_update)

    # 执行订单
    def execute_order(self, order):
        self.public_context.log_message('Execute order {}'.format(order))
        self.check_order(order.inst_id)

    # mock trader理论上不需要start和finish，为了统一性override一下，避免浪费cpu资源
    def start(self):
        self.public_context.log_message('Trader started.')

    def finish(self):
        print('Trader exited.')
        self.public_context.log_message('Trader exited.')



